/*
  基于Socket本地域（Unix域）实现多进程通信的 
  对于每一个通信的进程，通过线程实现
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <unistd.h>
#include <string.h>

#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/signal.h>

#define SOCK_PATH "/tmp/db2.sock"

#define SECRETY_KEY "disen666"

// 加密算法
void my_crypt(char *str){
    int i=0;
    int j=0;
    char *key = SECRETY_KEY;
    while(str[i]){
        str[i] = str[i] ^ key[j];
        i++;
        j++;
        if(j == strlen(key)) j=0;  // 密钥的字符从新开始
    }
}


// 负责与连接端（B端）进行通信
void *client_task(void *arg){
    int fd = *((int *)arg);
    printf("----客户端(fd=%d)已连接----\n",fd);
    char buf[256] = ""; 
    while(1){
        bzero(buf, 256);
        ssize_t len = read(fd, buf, 256);  // 阻塞的，等待数据到达再处理
        if(len > 0){
            if(strncmp(buf, "exit", 4) == 0) break;
            // 处理数据：加密运算
            my_crypt(buf);
            write(fd, buf, strlen(buf));
            usleep(200);
        }
    }
   printf("----客户端(fd=%d)已关闭----\n",fd);
   close(fd);
   return NULL;
}

void exit_signal_handler(int signum){
    unlink(SOCK_PATH);
    kill(getpid(), SIGABRT);
}

int main(int argc, char const *argv[])
{
    int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    if(sfd == -1) return -1;

    struct sockaddr_un addr = {AF_UNIX, SOCK_PATH};
    if(bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) != 0){
        perror("bind");
        return -1;
    }

    int cfd=0;
    listen(sfd, 10); // 必须设置，否则accept函数不会阻塞
    signal(SIGINT, exit_signal_handler);
    while(1){
        printf("---等待其它进程连接通信 --\n");
        cfd = accept(sfd, NULL, NULL);
        if(cfd > 0) {
            // 创建线程，负责与连接的进程进行通信
            pthread_t pid;
            pthread_create(&pid, NULL, client_task, &cfd);
            sleep(1); // 保证子线程运行
        }
    }
    return 0;
}
